package com.itheima.health.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.fastjson.JSON;
import com.itheima.health.dto.SetmealCount;
import com.itheima.health.exception.BusinessRuntimeException;
import com.itheima.health.service.ReportService;
import com.itheima.health.task.ReportJob;
import com.itheima.health.vo.HotSetmeal;
import com.itheima.health.vo.MemberReportVO;
import com.itheima.health.vo.ReportBussinessVO;
import com.itheima.health.vo.SetmealReportVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 数据报表service
 */
@Service
@Slf4j
public class ReportServiceImpl implements ReportService {
    @Autowired
    private StringRedisTemplate srt;
    @Autowired
    private ReportJob reportJob;

    /**
     * 获取近一年会员数
     * @return
     */
    @Override
    public MemberReportVO getMemberReport() {
        //查缓存
        HashOperations<String, Object, Object> opsForHash = srt.opsForHash();
        Object JsonMonths = opsForHash.get("member:year", "months");
        List<String> months = JSON.parseArray(JsonMonths.toString(), String.class);

        Object JsonMemberCount = opsForHash.get("member:year", "memberCount");
        List<Integer> memberCount = JSON.parseArray(JsonMemberCount.toString(), Integer.class);

        //缓存没有(-.-)
        if (memberCount.isEmpty() || months.isEmpty()){
            reportJob.getMemberReport();
        }

        return new MemberReportVO(months, memberCount);
    }

    /**
     * 套餐统计详情
     * @return
     */
    @Override
    public SetmealReportVo getSetmealReport() {

        //查缓存
        HashOperations<String, Object, Object> opsForHash = srt.opsForHash();
        List<String> setmealNames = JSON.parseArray(String.valueOf(opsForHash.get("setmeal:statistics", "setmealNames")), String.class);
        List<SetmealCount> setmealCount = JSON.parseArray(String.valueOf(opsForHash.get("setmeal:statistics", "setmealCounts")), SetmealCount.class);

        //缓存没有
        if (setmealCount.isEmpty() || setmealNames.isEmpty()){
            reportJob.getSetmealReport();
        }

        return new SetmealReportVo(setmealNames, setmealCount);
    }

    /**
     * 获取统计信息
     * @return
     */
    @Override
    public ReportBussinessVO getBusinessReportData() {
        //日期
        LocalDate now = LocalDate.now();
        //今日新增会员数
        Integer nowMemberNewCount = reportJob.getMemberCount(now, now);
        //本月新增会员数
        LocalDate firstMonthDay = YearMonth.from(now).atDay(1);
        Integer monthMemberNewCount = reportJob.getMemberCount(firstMonthDay, now);
        //本周新增会员数
        LocalDate monday = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        Integer weekMemberNewCount = reportJob.getMemberCount(monday, now);
        // 会员总数
        Integer totalMemberCount = reportJob.getMemberCount(null, now);

        //今日预约数
        Integer nowOrderCount = reportJob.getOrderCount(now, now, "");
        //今日到诊数
        Integer nowVisitCount = reportJob.getOrderCount(now, now, "已到诊");
        //本周预约数
        Integer weekOrderCount = reportJob.getOrderCount(monday, now, "");
        //本周到诊数
        Integer weekVisitCount = reportJob.getOrderCount(monday, now, "已到诊");
        //本月预约数
        Integer monthOrderCount = reportJob.getOrderCount(firstMonthDay, now, "");
        //本月到诊数
        Integer monthVisitCount = reportJob.getOrderCount(firstMonthDay, now, "已到诊");

        //热门套餐
        //刷一下缓存确保数据最新
        reportJob.getSetmealReport();
        //从缓存取
        HashOperations<String, Object, Object> opsForHash = srt.opsForHash();
        List<SetmealCount> setmealCounts = JSON.parseArray(String.valueOf(opsForHash.get("setmeal:statistics", "setmealCounts")), SetmealCount.class);
        //套参数求和
        Double totalSetmeal = setmealCounts.stream().mapToDouble(SetmealCount::getValue).sum();
        //热门套餐
        List<HotSetmeal> hotSetmeals = setmealCounts.stream().map(setmealCount -> {
            Integer value = setmealCount.getValue();
            Double rate = 0.0;
            rate = value / totalSetmeal;
            HotSetmeal hotSetmeal = HotSetmeal.builder()
                    .name(setmealCount.getName())
                    .proportion(rate)
                    .setmeal_count(setmealCount.getValue())
                    .build();
            return hotSetmeal;
        }).collect(Collectors.toList());

        return ReportBussinessVO.builder()
                .todayVisitsNumber(nowVisitCount)
                .reportDate(now)
                .todayNewMember(nowMemberNewCount)
                .thisWeekVisitsNumber(weekVisitCount)
                .hotSetmeal(hotSetmeals)
                .thisMonthNewMember(monthMemberNewCount)
                .thisWeekNewMember(weekMemberNewCount)
                .totalMember(totalMemberCount)
                .thisMonthOrderNumber(monthOrderCount)
                .thisMonthVisitsNumber(monthVisitCount)
                .todayOrderNumber(nowOrderCount)
                .thisWeekOrderNumber(weekOrderCount)
                .build();
    }

    /**
     * 导出报表
     * @param response
     */
    @Override
    public void exportBusinessReport(HttpServletResponse response) {
        //取数据
        ReportBussinessVO businessReportData = getBusinessReportData();
        List<HotSetmeal> hotSetmealList = businessReportData.getHotSetmeal();

        //输入输出流
        InputStream is = null;
        ServletOutputStream os = null;

        //设置请求头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + "report" + ".xlsx");

        try {
            is = this.getClass().getClassLoader().getResourceAsStream("report_template.xlsx");
            os = response.getOutputStream();
            //ExcelWrite带模板
            ExcelWriter excelWriter = EasyExcel.write(os).withTemplate(is).build();
            //填充
            excelWriter.fill(businessReportData, EasyExcel.writerSheet(0).build());
            excelWriter.fill(hotSetmealList, EasyExcel.writerSheet(0).build());
            excelWriter.finish();
            os.flush();
            is.close();
        }catch (Exception e){
            e.printStackTrace();
            throw new BusinessRuntimeException("报表导出失败，联系管理员");
        }
    }
}
